Thread: [HELP] C - pointers, structures and lists.

  1. #1
    Registered User
    Join Date
    Jun 2013
    Location
    Portugal
    Posts
    11

    [HELP] C - pointers, structures and lists.

    First of all, thanks for this community, although recently discovered by me it helped me many times just by reading some of your posts every once in a while.
    I've decided to join you now, not only to leech your wisdom but in the future to try and provide some, sadly, this is not the case today.

    Today at college it was proposed for us to make a C program for a distribution company.
    That company owns a warehouse where its products are stored, that warehouse its made of X corridors with Y closets, for the sake of this explanation lets assume 3 corridors each with 3 closets.
    In each closet theres the stock that the warehouse sells, each item of that stock its stored in a unique location (corridor and closet).
    It is also available to us a binary file organised this way:

    3 3
    3 10 3 20 2 30 3
    2 12 5 15 4
    1 9 7
    ...

    The first line of that file has 2 integers, one for the number of corridors the other for the closets.

    Second line, first digit indicates that there is 3 items stored in the closet 1 corridor 1, the product with the id "10" has 3 units, the product with the id "20" has 2, and the product with the id "30" has 3 units.

    Third line same thing but for closet 2, first digit indicates that there is 2 items stored in the closet 2 corridor 1, 5 units of "12" and 4 of "15"

    Fourth line has 1 item on closet 3 corridor 1, 7 units of "9".

    The next line would be for closet 1 but now in corridor 2.

    But my problem here it's not coding itself, its logic.

    I want to read from that binary file and allocate all that info logically structured into memory so I can later manipulate it for like listing available stock, restocking, etc.. .

    I know I'll have to use dynamic structures, the number of closets and corridors won't change while the program is executing but the quantity and variety of products in each closet will.

    What would be your approach?

    Thank you.

  2. #2
    Registered User
    Join Date
    Apr 2013
    Posts
    1,658
    You could use linked lists or arrays (along with pointers and info about the arrays), but linked lists may be easier. One thing that isn't clear is if all X corridors will have exactly Y closets, or if the number of closets per corridor can vary.

  3. #3
    Registered User
    Join Date
    Jun 2013
    Location
    Portugal
    Posts
    11
    Thank you for your reply!
    And yes, all X corridors will have exactly Y closets, no corridor can have a different amount of closets.
    Could you explain better the use of linked lists? As far as my knowledge goes in that matter its something like a structure:

    Code:
    struct products {
          int id;
          int quantity;
          struct products *pprox;
    }
    This would give me a structure of products with 2 fields and a pointer to the next node, but I can't see how could I relate the entire list of products to a certain closet in a certain corridor.

    Thank you.

  4. #4
    Registered User migf1's Avatar
    Join Date
    May 2013
    Location
    Athens, Greece
    Posts
    385
    Quote Originally Posted by rcgldr View Post
    You could use linked lists or arrays (along with pointers and info about the arrays), but linked lists may be easier. One thing that isn't clear is if all X corridors will have exactly Y closets, or if the number of closets per corridor can vary.
    Wouldn't that be a 2d array of linked-lists, or have I gotten it wrong?
    Since corridors and lockers are fixed, I was thinking something like...

    Code:
    Product *storage[corridors][lockers];

  5. #5
    Registered User
    Join Date
    Jun 2013
    Location
    Portugal
    Posts
    11
    Thanks migf1, that actually made logical sense to me.
    But could you give me an example on how would my structure(s) be declared and an example on how could I say that P product its stored in X corridor and Y closet?.

    Thank you.


    EDIT: The number of closets and corridors are only known when the program reads from the binary file, they don't change after that. So I can only declare that 2d array after the program reads from the file.
    Last edited by sigkill; 06-05-2013 at 05:24 PM.

  6. #6
    Registered User migf1's Avatar
    Join Date
    May 2013
    Location
    Athens, Greece
    Posts
    385
    Quote Originally Posted by sigkill View Post
    Thanks migf1, that actually made logical sense to me.
    But could you give me an example on how would my structure(s) be declared and an example on how could I say that P product its stored in X corridor and Y closet?.

    Thank you.
    Code:
    #define NCORRIDORS 3
    #define NLOCKERS   3
    
    typedef struct Product Product;
    struct Product {
        int id;
        int nitems;
        Product *next;
    };
    ...
    bool product_append( Product **head, int id, int nitems );
    ...
    int main( void )
    {
        Product *storage[NCORRIDORS][NLOCKERS] = {NULL};
        ...
        /* the 2nd line of the file (the one that describes 1st corridor, 1st locker) */
        product_append( &storage[0][0], 10, 3);
        product_append( &storage[0][0], 20, 2);
        product_append( &storage[0][0], 30, 3);
    }
    EDIT:

    In response to your edit, if you are using C99+ you can read the 1st line of the file and then define storage as a VLA. If you are using C89/C90, you can allocate it dynamically.
    Last edited by migf1; 06-05-2013 at 05:56 PM. Reason: typos

  7. #7
    Registered User
    Join Date
    Apr 2013
    Posts
    1,658
    I prefer to put the linkage pointer before the data so that common code can be used to work with lists (by casting to some basic node type). Corridors have a linked list of closets, and closets have a linked list of products:

    Code:
    typedef struct _node{
        struct _node *next;
    }node_t, *pnode_t;
    
    typedef struct _product{
        struct _product *next;
        int id;
        int quantity;
    }product_t, *pproduct_t; 
    
    typedef struct _closet{
        struct _closet *next;
        pproduct_t ptrtofirstproduct;
    }closet_t, *pcloset_t;
       
    typedef struct _corridor{
        struct _corridor * next;
        pcloset_t ptrtofirstcloset;
    }corridor_t, *pcorridor_t;
    Using microsoft 'C' convention of using uppercase for typedefs:

    Code:
    typedef struct _NODE{
        struct _NODE *next;
    }NODE, *PNODE;
    
    typedef struct _PRODUCT{
        struct _PRODUCT *next;
        int id;
        int quantity;
    }PRODUCT, *PPRODUCT; 
    
    typedef struct _CLOSET{
        struct _CLOSET *next;
        PPRODUCT ptrtofirstproduct;
    }CLOSET, *PCLOSET;
       
    typedef struct _CORRIDOR{
        struct _CORRIDOR * next;
        PCLOSET ptrtofirstcloset;
    }CORRIDOR, *PCORRIDOR;
    Last edited by rcgldr; 06-05-2013 at 05:46 PM.

  8. #8
    Registered User migf1's Avatar
    Join Date
    May 2013
    Location
    Athens, Greece
    Posts
    385
    TBH, I'm not a fan of hiding pointers inside custom data types, unless it is absolutely necessary (e.g. when implementing opaque objects, say as part of a library). They make code more hard to read, but your mileage may vary.

    I also beleive that in this particular case, it's kinda of an overkill to have all those structs defined separately. Product is the only custom type that is really needed throughout the whole program imho. No need for casting, or other generic (and/or OOP) programming techniques.

  9. #9
    Registered User
    Join Date
    Apr 2013
    Posts
    1,658
    Quote Originally Posted by migf1 View Post
    I'm not a fan of hiding pointers inside custom data types.
    It's somewhat common with microsoft and the windows API, but I'll change this to not hide the pointers and use somewhat shorter names:

    Code:
    typedef struct _NODE{
        struct _NODE *next;
    }NODE, *PNODE;
    
    typedef struct _PRODUCT{
        struct _PRODUCT *next;
        int id;
        int quantity;
    }PRODUCT, *PPRODUCT; 
    
    typedef struct _CLOSET{
        struct _CLOSET *next;
        PRODUCT *ptr2product;
    }CLOSET, *PCLOSET;
       
    typedef struct _CORRIDOR{
        struct _CORRIDOR * next;
        CLOSET *ptr2closet;
    }CORRIDOR, *PCORRIDOR;
    Note since the result of all this will be somewhat tree like, the original poster might want to consider using recursive functions (one function for each structure type for each search or scan type) to navigate the tree.

    Quote Originally Posted by migf1 View Post
    I also beleive that in this particular case, it's kinda of an overkill to have all those structs defined separately.
    True, you could just have a flat array or list of product structures that included corridors and closets as members, but I think the ideal of the assignment is to have some sort of tree like structure where corridors have closets, and closets have products.
    Last edited by rcgldr; 06-05-2013 at 06:27 PM.

  10. #10
    Registered User
    Join Date
    Apr 2013
    Posts
    1,658
    Quote Originally Posted by rcgldr View Post
    True, you could just have a flat array or list of product structures that included corridors and closets as members, but I think the ideal of the assignment is to have some sort of tree like structure where corridors have closets, and closets have products.
    It possible that the program might need both methods. For example, trying to handle a query to produce a sorted list of all products by id and quantity, or a list sorted by product id, corridor id, closet id, quantity, ...

    This could be handled with an array of pointers to all products and adding corridor id and closet id to the product structure, or there could yet another list or array of structures based on product id, corridor id, closet id, quantity.
    Last edited by rcgldr; 06-05-2013 at 07:51 PM.

  11. #11
    Registered User migf1's Avatar
    Join Date
    May 2013
    Location
    Athens, Greece
    Posts
    385
    Yeap, in broad context everything goes I guess (even using a 3d party database system like mySql, in the first place ).
    Last edited by migf1; 06-06-2013 at 05:35 AM.

  12. #12
    Registered User
    Join Date
    Jun 2013
    Location
    Portugal
    Posts
    11
    Thank you both migf1 and rcgldr !
    I must admit yesterday I was like "Man, their explanations just turned this harder to understand!" but finally I got it, or at least I scratched it a bit.
    I ended up using three structures like rcgldr said.
    Code:
    typedef struct corridor corr, *corr_ptr;
    typedef struct closets clost, *closet_ptr;
    typedef struct products prods, *prod_ptr;
    
    struct products {
        int id;
        int qty;
        prod_ptr next;
    }
    
    struct closet {
       int number;
       int number_of_products;
       closet_ptr next;
       prod_ptr pointer_to_products;
    }
    
    struct corridor
    {
       int number;
       closet_ptr pointer_to_closet;
    corr_ptr next;
    }

  13. #13
    Registered User
    Join Date
    Apr 2013
    Posts
    1,658
    Quote Originally Posted by sigkill View Post
    I ended up using three structures ...
    Note if you move the "next" pointers to be the first variable in a structure as shown in my example, then you can use common code to add or remove a structure from a list (with my example you would cast the pointer to a structure to (NODE *) ). When the program is reading in the file, you should keep local pointers to the last structure in each list of structures, to avoid having to search through a list each time you want to add a structure to the end of a list. A more generic solution would have pointers to the first and last sub structure in a structure, but since this program only builds the list one time, using local pointers is OK. The generic version of this would look like:

    Code:
    typedef struct _SUBNODE{
        struct _SUBNODE * next;
    }SUBNODE, *PSUBNODE;
    
    typedef struct _NODE{
        struct _NODE * next;
        SUBNODE * first;
        SUBNODE * last;
    }NODE, *PNODE;
    Last edited by rcgldr; 06-07-2013 at 12:18 PM.

  14. #14
    Registered User
    Join Date
    Jun 2013
    Location
    Portugal
    Posts
    11
    Thank you for your tip!. I'll definitely try it out once I get this sorted out.

    I now encounter a new challenge (just using corridors and closets):

    Code:
    
    typedef struct corredores corrs, *ptr_corr;
    typedef struct armarios armrs, *ptr_armr;
    
    
    struct corredores {
        int id;
        ptr_armr pont_armario;
        ptr_corr prox;
    };
    struct armarios {
        int id;
        int nr_prods;
        ptr_armr prox;
    };
    int main()
    {
        ptr_corr lista = NULL;
        
        
        lista = carrega_lista(lista);
        mostra_lista(lista);
    }
    
    
    ptr_corr carrega_lista(ptr_corr p)
    {
        int i, nr_cors=0, nr_arms=0;
        ptr_corr novo, aux;
        FILE *f = fopen(FILENAME, RDMODE);
        
        fread(&nr_cors,sizeof(int),1,f);
        fread(&nr_arms,sizeof(int),1,f);
        fclose(f);
        
        for(i=0; i < nr_cors; i++){
            novo = malloc(sizeof(corrs));
            if(novo == NULL)
            {
                printf("Erro ao alocar memoria!\n");
                return p;
            }
            novo->id = i+1;
            novo->pont_armario = NULL;
            novo->prox = NULL;
            
            if(p == NULL)
                p = novo;
            else
            {
                aux = p;
                while(aux->prox != NULL)
                    aux = aux->prox;
                aux->prox = novo;
            }
        }
        carrega_armario(p, nr_arms);
    
    
        return p;
    }
    void carrega_armario(ptr_corr p, int nr_armarios)
    {
        
        ptr_armr novo;
        int j=0;
     
        while(p != NULL)
        {
            for(j=nr_armarios; j > 0; j--){
            
                novo = malloc(sizeof(armrs));
                novo->id = j;
                novo->nr_prods = 0;
                novo->prox = p->pont_armario;
                p->pont_armario = novo;
            }
            p = p->prox;
        }
        fclose(f);
    }
    As you can see the first function creates the nodes that are the corridors and then calls for a second function passing the pointer p of the corridor struct and the number of closets that it was read from fread before.
    This second function does pretty much the same thing but for closets, but it's set to save the closet nodes at the beginning of the list and I want it to be at the end (thats why I did that inverted for ). How can I do this?

    Also, is there any problem that I'm not returning the pointer to the closet list as I did with corridors?

    Thank you!

  15. #15
    Registered User
    Join Date
    Apr 2013
    Posts
    1,658
    You changed the order of the structure declarations, and you separated the typedefs. I don't know if C is supposed to support forward references like this. If not, you should change the code to combine the typedefs with the structure declarations and declare them in the order I did in my earlier examples.

    Another issue is that you should use fgets() to get one line of text data at a time from the input file, then use sscanf() to read the values from each line.

    Quote Originally Posted by sigkill View Post
    second function ... set to save nodes at the beginning of the list.
    You can either follow a list to get to the end each time as you did with the first function. or keep a local pointer to the last structure on the list (or NULL), and use that.
    Last edited by rcgldr; 06-07-2013 at 04:59 PM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Link Lists of Structures within Structures...
    By Zocheyado in forum C Programming
    Replies: 3
    Last Post: 04-17-2012, 04:21 PM
  2. Understanding linked lists, structures, and pointers
    By yougene in forum C Programming
    Replies: 5
    Last Post: 07-13-2011, 08:13 PM
  3. Can i do this: Structures and linked lists help
    By satory in forum C Programming
    Replies: 4
    Last Post: 04-25-2005, 07:49 AM
  4. structures/linked lists
    By xddxogm3 in forum C++ Programming
    Replies: 4
    Last Post: 09-27-2003, 11:06 PM
  5. Replies: 5
    Last Post: 04-11-2002, 11:29 AM